#include "PCH.h"
#include "ShaderManager.h"
#include "ShaderFactory.h"
#include "VertexShader.h"
#include "HullShader.h"
#include "DomainShader.h"
#include "GeometryShader.h"
#include "PixelShader.h"
#include "ComputeShader.h"

using namespace DeviousRenderer;

ShaderManager::ShaderManager(ID3D11Device* d3dDevice, ID3D11DeviceContext* d3dDeviceContext)
	: m_pDeviceRef(d3dDevice)
	, m_pDeviceContextRef(d3dDeviceContext)
{

}

ShaderManager::~ShaderManager()
{
}

int ShaderManager::LoadShader(ShaderType type, std::wstring& fileName, std::wstring& mainFunction, const D3D_SHADER_MACRO* pDefines)
{
	HRESULT hr = S_OK;

	ID3DBlob* pCompileShader = ShaderFactory::CompileShader(type, fileName, mainFunction, pDefines);
	if (NULL == pCompileShader)
	{
		return -1;
	}

	DeShader* pShaderWrapper = 0;
	switch(type)
	{
	case VERTEX_SHADER:
		{
			ID3D11VertexShader* pShader = 0;
			hr = m_pDeviceRef->CreateVertexShader(pCompileShader->GetBufferPointer(), pCompileShader->GetBufferSize(), 0, &pShader);
			pShaderWrapper = new VertexShader(pShader);
			break;
		}
	case HULL_SHADER:
		{
			ID3D11HullShader* pShader = 0;
			hr = m_pDeviceRef->CreateHullShader(pCompileShader->GetBufferPointer(), pCompileShader->GetBufferSize(), 0, &pShader);
			pShaderWrapper = new HullShader(pShader);
			break;
		}		
	case DOMAIN_SHADER:
		{
			ID3D11DomainShader* pShader = 0;
			hr = m_pDeviceRef->CreateDomainShader(pCompileShader->GetBufferPointer(), pCompileShader->GetBufferSize(), 0, &pShader);
			pShaderWrapper = new DomainShader(pShader);
			break;
		}
	case PIXEL_SHADER:
		{
			ID3D11PixelShader* pShader = 0;
			hr = m_pDeviceRef->CreatePixelShader(pCompileShader->GetBufferPointer(), pCompileShader->GetBufferSize(), 0, &pShader);
			pShaderWrapper = new PixelShader(pShader);
			break;
		}
	case GEOMETRY_SHADER:
		{
			ID3D11GeometryShader* pShader = 0;
			hr = m_pDeviceRef->CreateGeometryShader(pCompileShader->GetBufferPointer(), pCompileShader->GetBufferSize(), 0, &pShader);
			pShaderWrapper = new GeometryShader(pShader);
			break;
		}
	case COMPUTER_SHADER:
		{
			ID3D11ComputeShader* pShader = 0;
			hr = m_pDeviceRef->CreateComputeShader(pCompileShader->GetBufferPointer(), pCompileShader->GetBufferSize(), 0, &pShader);
			pShaderWrapper = new ComputeShader(pShader);
			break;
		}
	}
	std::wstringstream message;
	if (FAILED(hr))
	{
		message<<"Failed to create shader!";
		SAFE_RELEASE(pCompileShader);
		SAFE_DELETE(pShaderWrapper);
		return -1;
	}
	pShaderWrapper->m_sFileName = fileName;
	pShaderWrapper->m_pCompiledShader = pCompileShader;
	m_vShaders.push_back(pShaderWrapper);

	return m_vShaders.size()-1;
}

void ShaderManager::BindShaders()
{
	DeShader* shader = NULL;
	for (int i = 0; i < SHADER_TYPE_NUM; i ++)
	{
		shader = GetShader((ShaderType)i);
		if (shader)
		{
			shader->Bind(m_pDeviceContextRef);
		}
	}
}

void ShaderManager::UpdateShaderResources()
{

}

DeShader* ShaderManager::GetShader(ShaderType shaderType)
{
	int shaderIndex = m_ShaderBindingStates[shaderType];
	if (shaderIndex != -1 && (int)shaderIndex < m_vShaders.size())
	{
		return m_vShaders[shaderIndex];
	}

	return NULL;
}

